Creating the environment for the project

  • Creating conda environment :

    conda create -n pong python=3.7 -y

  • Activating the conda environment :

    conda activate pong

  • Installing Libraries :

    pip install opencv-python

    pip install cvzone

  • For this project we are using cvzone package to detect hand gesture and overlaying images. You can explore about the packages here

Now Importing required modules

import cv2
import cvzone
from cvzone.HandTrackingModule import HandDetector
import numpy as np
  • Importing the required images
imgBackground = cv2.imread("images/Background.png")
imgGameOver = cv2.imread("images/gameOver.png")
imgBall = cv2.imread("images/Ball.png", cv2.IMREAD_UNCHANGED)
imgBat1 = cv2.imread("images/bat1.png", cv2.IMREAD_UNCHANGED)
imgBat2 = cv2.imread("images/bat2.png", cv2.IMREAD_UNCHANGED)

Logic of the game :

  • First read the frame by taking images using OpenCV.
  • Fliping the image horizontally using **cv2.flip** function available on OpenCV.
  • Setting variables as ballPos for initial place of ball speedX and speedY for initial speed of ball, gameOver is False as a initial value and we set a score as a dictionary and put 0 as a value since during a gameplay we can add the score and store on that.
  • We overlay the images using **cv2.addWeighted** to display the original images read by opencv.

  • Check for hand section :

    • After finding hand coordinates using cvzone findhands method we also take the shape of bat images and perform the operation to set our hands positions in the middle of bat.
    • We use numpy np.clip function to set our bat inside the image only.
    • Now if the hand is left we overlay bat1 images in the gameover image which is already overlayed in frame image.
      • Again to make sure ball is just hitting the bat we set a if condition and if true we reverse the speed of the ball and increase the score by 1. Here we increment ballPos[0] by 30 to make visual effect that ball just hit the bat
      • We do same for right hand.
  • Now we check if the game is over or not by setting the if condition where if ballPos is below its limit and above its limit.

    • If game is over then we display the game over images where total score is displayed.

    • If game is not over then keep continuing the game by displaying the scores.

  • Finally we set a condition to replay the game when it is over by hitting r key in keyboard.

cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)
 
# Hand Detector
detector = HandDetector(detectionCon=0.8, maxHands=2)
 
# Variables
ballPos = [100, 100]
speedX = 15
speedY = 15
gameOver = False
score = [0, 0]
 
while True:
    _, img = cap.read()
    img = cv2.flip(img, 1)
    imgRaw = img.copy()
 
    # Find the hand and its landmarks
    hands, img = detector.findHands(img, flipType=False)  # with draw
 
    # Overlaying the background image
    img = cv2.addWeighted(img, 0.4, imgBackground, 0.6, 0)
 
    # Check for hands
    if hands:
        for hand in hands:
            x, y, w, h = hand['bbox']
            h1, w1, _ = imgBat1.shape
            y1 = y - h1 // 2
            y1 = np.clip(y1, 20, 415)
 
            if hand['type'] == "Left":
                img = cvzone.overlayPNG(img, imgBat1, (59, y1))
                if 59 < ballPos[0] < 59 + w1 and y1 < ballPos[1] < y1 + h1:
                    speedX = -speedX
                    ballPos[0] += 30
                    score[0] += 1
 
            if hand['type'] == "Right":
                img = cvzone.overlayPNG(img, imgBat2, (1195, y1))
                if 1195 - 50 < ballPos[0] < 1195 and y1 < ballPos[1] < y1 + h1:
                    speedX = -speedX
                    ballPos[0] -= 30
                    score[1] += 1
 
    # Game Over
    if ballPos[0] < 40 or ballPos[0] > 1200:
        gameOver = True
 
    if gameOver:
        img = imgGameOver
        cv2.putText(img, str(score[1] + score[0]).zfill(2), (585, 360), cv2.FONT_HERSHEY_COMPLEX,
                    2.5, (200, 0, 200), 5)
 
    # If game not over move the ball
    else:
 
        # Move the Ball
        if ballPos[1] >= 500 or ballPos[1] <= 10:
            speedY = -speedY
 
        ballPos[0] += speedX
        ballPos[1] += speedY
 
        # Draw the ball
        img = cvzone.overlayPNG(img, imgBall, ballPos)
 
        cv2.putText(img, str(score[0]), (300, 650), cv2.FONT_HERSHEY_COMPLEX, 3, (255, 255, 255), 5)
        cv2.putText(img, str(score[1]), (900, 650), cv2.FONT_HERSHEY_COMPLEX, 3, (255, 255, 255), 5)
 
    img[580:700, 20:233] = cv2.resize(imgRaw, (213, 120))
 
    cv2.imshow("Image", img)
    key = cv2.waitKey(1)
    if key == ord('r'):
        ballPos = [100, 100]
        speedX = 15
        speedY = 15
        gameOver = False
        score = [0, 0]
        imgGameOver = cv2.imread("images/gameOver.png")